home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / gnu / gnulib / ohlutil / backupfi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-08-24  |  8.8 KB  |  355 lines

  1. /* backupfile.c -- make Emacs style backup file names
  2.    Copyright (C) 1990 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 1, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* David MacKenzie <djm@ai.mit.edu>.
  19.    Some algorithms adapted from GNU Emacs. */
  20.  
  21. /*
  22.  * MS-DOS port (c) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet
  23.  *
  24.  * To this port, the same copying conditions apply as to the
  25.  * original release.
  26.  *
  27.  * IMPORTANT:
  28.  * This file is not identical to the original GNU release!
  29.  * You should have received this code as patch to the official
  30.  * GNU release.
  31.  *
  32.  * MORE IMPORTANT:
  33.  * This port comes with ABSOLUTELY NO WARRANTY.
  34.  *
  35.  * $Header: e:/gnu/fileutil/RCS/backupfi.c'v 1.3.0.4 90/06/29 14:24:17 tho Exp $
  36.  */
  37.  
  38. #include <ctype.h>
  39. #include <sys/types.h>
  40. #include "backupfile.h"
  41. #if defined(USG) || defined(_POSIX_SOURCE)
  42. #define index strchr
  43. #define rindex strrchr
  44. #include <string.h>
  45. #else
  46. #include <strings.h>
  47. #endif
  48.  
  49. #ifdef MSDOS
  50.  
  51. #include <stdio.h>
  52.  
  53. extern char *find_backup_file_name (char *file);
  54. static int max_backup_version (char *file, char *dir);
  55. static char *make_version_name (char *file, int version);
  56. static int version_number (char *base, char *backup, int base_length);
  57. static char *dirname (char *path);
  58. static char *basename (char *name);
  59. static char *concat (char *str1, char *str2);
  60. static char *copystring (char *str);
  61. static char *chop_filename (char *path, int n);
  62.  
  63. #include "msd_dir.h"
  64. #define NLENGTH(direct) ((direct)->d_namlen)
  65.  
  66. #else /* not MSDOS */
  67.  
  68. #ifdef DIRENT
  69. #include <dirent.h>
  70. #define direct dirent
  71. #define NLENGTH(direct) (strlen((direct)->d_name))
  72. #else
  73. #define NLENGTH(direct) ((direct)->d_namlen)
  74. #ifdef USG
  75. #ifdef SYSNDIR
  76. #include <sys/ndir.h>
  77. #else
  78. #include <ndir.h>
  79. #endif
  80. #else /* must be BSD */
  81. #include <sys/dir.h>
  82. #endif
  83. #endif
  84.  
  85. #endif /* not MSDOS */
  86.  
  87. #ifdef STDC_HEADERS
  88. #include <stdlib.h>
  89. #define ISDIGIT(c) (isdigit ((unsigned char) (c)))
  90. #else
  91. #define ISDIGIT(c) (isascii (c) && isdigit (c))
  92.  
  93. char *malloc ();
  94. #endif
  95.  
  96. /* Which type of backup file names are generated. */
  97. enum backup_type backup_type = none;
  98.  
  99. /* The extension added to file names to produce a simple (as opposed
  100.    to numbered) backup file name. */
  101. char *simple_backup_suffix = "~";
  102.  
  103. static char *basename ();
  104. static char *concat ();
  105. static char *copystring ();
  106. static char *dirname ();
  107. char *find_backup_file_name ();
  108. static char *make_version_name ();
  109. static int max_backup_version ();
  110. static int version_number ();
  111.  
  112. /* Return the name of the new backup file for file FILE,
  113.    allocated with malloc.  Return 0 if out of memory.
  114.    FILE must not end with a '/' unless it is the root directory.
  115.    Do not call this function if backup_type == none. */
  116.  
  117. char *
  118. find_backup_file_name (file)
  119.      char *file;
  120. {
  121.   char *dir;
  122.   char *base_versions;
  123.   int highest_backup;
  124.  
  125.   if (backup_type == simple)
  126.     return concat (file, simple_backup_suffix);
  127.   base_versions = concat (basename (file), ".~");
  128.   if (base_versions == 0)
  129.     return 0;
  130.   dir = dirname (file);
  131.   if (dir == 0)
  132.     {
  133.       free (base_versions);
  134.       return 0;
  135.     }
  136.   highest_backup = max_backup_version (base_versions, dir);
  137.   free (base_versions);
  138.   free (dir);
  139.   if (backup_type == numbered_existing && highest_backup == 0)
  140.     return concat (file, simple_backup_suffix);
  141.   return make_version_name (file, highest_backup + 1);
  142. }
  143.  
  144. /* Return the number of the highest-numbered backup file for file
  145.    FILE in directory DIR.  If there are no numbered backups
  146.    of FILE in DIR, return 0.
  147.    FILE should already have ".~" appended to it. */
  148.  
  149. static int
  150. max_backup_version (file, dir)
  151.      char *file, *dir;
  152. {
  153.   DIR *dirp;
  154.   struct direct *dp;
  155.   int highest_version;
  156.   int this_version;
  157.   int file_name_length;
  158.   
  159.   dirp = opendir (dir);
  160.   if (!dirp)
  161.     return 0;
  162.   
  163.   highest_version = 0;
  164.   file_name_length = strlen (file);
  165.  
  166.   while ((dp = readdir (dirp)) != 0)
  167.     {
  168. #ifdef MSDOS
  169.       if (NLENGTH (dp) <= file_name_length)
  170. #else /* not MSDOS */
  171.       if (dp->d_ino == 0 || NLENGTH (dp) <= file_name_length)
  172. #endif /* not MSDOS */
  173.     continue;
  174.       
  175.       this_version = version_number (file, dp->d_name, file_name_length);
  176.       if (this_version > highest_version)
  177.     highest_version = this_version;
  178.     }
  179.   closedir (dirp);
  180.   return highest_version;
  181. }
  182.  
  183. #ifdef MSDOS
  184. static char suffix[5];
  185. #endif /* not MSDOS */
  186.  
  187. /* Return a string, allocated with malloc, containing
  188.    "FILE.~VERSION~".  Return 0 if out of memory. */
  189.  
  190. static char *
  191. make_version_name (file, version)
  192.      char *file;
  193.      int version;
  194. {
  195. #ifdef MSDOS
  196.   sprintf (suffix, ".~%.1d~", version);
  197.   return concat (file, suffix);
  198. #else /* not MSDOS */
  199.   char *backup_name;
  200.  
  201.   backup_name = malloc (strlen (file) + 16);
  202.   if (backup_name == 0)
  203.     return 0;
  204.   sprintf (backup_name, "%s.~%d~", file, version);
  205.   return backup_name;
  206. #endif /* not MSDOS */
  207. }
  208.  
  209. /* If BACKUP is a numbered backup of BASE, return its version number;
  210.    otherwise return 0.  BASE_LENGTH is the length of BASE.
  211.    BASE should already have ".~" appended to it. */
  212.  
  213. static int
  214. version_number (base, backup, base_length)
  215.      char *base;
  216.      char *backup;
  217.      int base_length;
  218. {
  219.   int version;
  220.   char *p;
  221.  
  222.   version = 0;
  223.   if (!strncmp (base, backup, base_length) && ISDIGIT (backup[base_length]))
  224.     {
  225.       for (p = &backup[base_length]; ISDIGIT (*p); ++p)
  226.     version = version * 10 + *p - '0';
  227. #ifdef MSDOS
  228.       if (*p && *p != '~')
  229. #else /* not MSDOS */
  230.       if (p[0] != '~' || p[1])
  231. #endif /* not MSDOS */
  232.     version = 0;
  233.     }
  234.   return version;
  235. }
  236.  
  237. /* Return the leading directories part of PATH,
  238.    allocated with malloc.  If out of memory, return 0. */
  239.  
  240. static char *
  241. dirname (path)
  242.      char *path;
  243. {
  244.   char *newpath;
  245.   char *slash;
  246.   char *scan;
  247.  
  248.   slash = rindex (path, '/');
  249.   if (slash == 0)
  250.     return copystring (".");
  251.  
  252.   newpath = malloc (strlen (path) + 1);
  253.   if (newpath == 0)
  254.     return 0;
  255.   strcpy (newpath, path);
  256.   slash += newpath - path;
  257.   /* Remove any trailing slashes and final element. */
  258.   for (scan = slash; scan > newpath && *scan == '/'; --scan)
  259.     /* Do nothing. */ ;
  260.   if (scan > newpath)
  261.     scan[1] = 0;
  262.   return newpath;
  263. }
  264.  
  265. /* Return NAME with any leading path stripped off.  */
  266.  
  267. static char *
  268. basename (name)
  269.      char *name;
  270. {
  271.   char *base;
  272.  
  273.   base = rindex (name, '/');
  274.   return base ? base + 1 : name;
  275. }
  276.  
  277. /* Return the newly-allocated concatenation of STR1 and STR2.
  278.    If out of memory, return 0. */
  279.  
  280. static char *
  281. concat (str1, str2)
  282.      char *str1, *str2;
  283. {
  284.   char *newstr;
  285.   char str1_length = strlen (str1);
  286.  
  287. #ifdef MSDOS
  288.   /* The MS-DOS version tries to squeeze the given string into a valid
  289.      MS-DOS patch name.  STR1 is chopped and a leading period is removed
  290.      from STR2.  Kludge: a leading period is counted in the length of STR2,
  291.      this is because we will know, that in this case a digit will be appended
  292.      afterwards.  */
  293.   /* chop_filename () might add a '.', so allocate one more byte.  */
  294.   newstr = malloc (str1_length + strlen (str2) + 2);
  295.   if (newstr == 0)
  296.     return 0;
  297.   strcpy (newstr, str1);
  298.   chop_filename (newstr, min (2, strlen(str2)));
  299.   if (*str2 == '.')
  300.     str2++;
  301.   strcat (newstr, str2);
  302. #else /* not MSDOS */
  303.   newstr = malloc (str1_length + strlen (str2) + 1);
  304.   if (newstr == 0)
  305.     return 0;
  306.   strcpy (newstr, str1);
  307.   strcpy (newstr + str1_length, str2);
  308. #endif /* not MSDOS */
  309.   return newstr;
  310. }
  311.  
  312. /* Return a newly allocated copy of STR. */
  313.  
  314. static char *
  315. copystring (str)
  316.      char *str;
  317. {
  318.   char *newstr;
  319.   
  320.   newstr = malloc (strlen (str) + 1);
  321.   if (newstr == 0)
  322.     return 0;
  323.   strcpy (newstr, str);
  324.   return newstr;
  325. }
  326.  
  327.  
  328. #ifdef MSDOS
  329. /* Shorten a MS-DOS path to accomodate a backup suffix.  */
  330.  
  331. char *
  332. chop_filename (char *path, int n)
  333. {
  334.   char *base;
  335.   char *suffix;
  336.  
  337.   base = strrchr (path, '/');
  338.   if (base == (char *)0)
  339.     base = path;
  340.   else
  341.     base++;
  342.  
  343.   suffix = strchr (base, '.');
  344.   if (suffix == (char *)0)
  345.     strcat (base, ".");        /* is ok, since we have allocated enough! */
  346.   else if (strlen (suffix) >= 4 - n)
  347.     suffix[4-n] = '\0';
  348.  
  349.   return path;
  350. }
  351. #endif /* MSDOS */
  352.  
  353.  
  354.  
  355.